import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * ftp utils
 */
@Slf4j
public class FTPConnector {
    private static final int FTP_PORT = 21;
    /**
     * TODO:fill in ip, user_name and password when deploying
     */
    private static final String USER_NAME = "ULSSFTP";
    private static final String PASSWORD = "eNm6SpXdL7MdH2Cf";
    private static final FTPClient FTP_CLIENT = new FTPClient();
    private static final String FTP_IP = "129.211.208.94";

    public static boolean connectFTP() throws Exception {
        FTP_CLIENT.connect(FTP_IP, FTP_PORT);
        FTP_CLIENT.login(USER_NAME, PASSWORD);
        int replyCode = FTP_CLIENT.getReplyCode();
        return FTPReply.isPositiveCompletion(replyCode);
    }

    public static Boolean downloadFile(String filePath, String fileName, String downloadPath) {
        boolean flag = false;
        try {
            FTP_CLIENT.changeWorkingDirectory(filePath);
            FTP_CLIENT.enterLocalPassiveMode();
            FTPFile[] files = FTP_CLIENT.listFiles();

            File directory = new File(downloadPath);
            if (!directory.exists()) {
                directory.mkdirs();
            }

            for (FTPFile file : files) {
                if (file.getName().equals(fileName)) {
                    File downFile = new File(downloadPath + File.separator + file.getName());
                    OutputStream out = new FileOutputStream(downFile);
                    flag = FTP_CLIENT.retrieveFile(new String(file.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), out);
                    out.flush();
                    out.close();
                }
            }
        } catch (Exception e) {
            log.warn("download from ftp failed!");
            flag = false;
            e.printStackTrace();
        }
        return flag;
    }

    public static Boolean downloadAllFiles(String filePath, String downloadPath) {
        boolean flag = false;
        try {
            FTP_CLIENT.changeWorkingDirectory(filePath + "/");
            FTP_CLIENT.enterLocalPassiveMode();
            FTPFile[] files = FTP_CLIENT.listFiles();

            for (FTPFile file : files) {
                File downFile = new File(downloadPath + file.getName());
                OutputStream out = new FileOutputStream(downFile);
                flag = FTP_CLIENT.retrieveFile(new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"), out);
                out.flush();
                out.close();
                if (!flag) {
                    break;
                }
            }
            return flag;
        } catch (Exception e) {
            log.warn("download from ftp failed!");
            flag = false;
            e.printStackTrace();
        }
        return true;
    }

    public static Boolean uploadFile(String fileName) {
        String ftpPath = ZookeeperManager.getPath();
        //TODO: change this path
        String uploadPath = "D:\\Coding\\ULSS-miniSQL\\ulss-distributed-mini-sql\\Code\\RegionServer\\";

        boolean flag = false;
        InputStream in = null;
        try {
            FTP_CLIENT.enterLocalPassiveMode();
            FTP_CLIENT.setFileType(FTPClient.BINARY_FILE_TYPE);
            if (!FTP_CLIENT.changeWorkingDirectory(ftpPath)) {
                FTP_CLIENT.makeDirectory(ftpPath);
            }
            FTP_CLIENT.changeWorkingDirectory(ftpPath);

            File file = new File(uploadPath + fileName);
            in = new FileInputStream(file);
            String tempName = ftpPath + File.separator + file.getName();
            flag = FTP_CLIENT.storeFile(new String(tempName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1), in);
        } catch (Exception e) {
            log.warn("upload to ftp failed!");
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }
}
